package com.starsoft.quant.web;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;

import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

import com.starsoft.frame.base.bean.BaseAcount;
import com.starsoft.frame.base.bean.UserContext;
import com.starsoft.frame.base.plugin.AcountPluginService;
import com.starsoft.frame.base.service.AcountService;
import com.starsoft.frame.base.service.UserService;
import com.starsoft.frame.core.web.WebUtil;
import com.starsoft.frame.util.StringUtil;
import com.starsoft.quant.bean.QuantAcount;
import com.starsoft.quant.bean.QuantModelParam;
import com.starsoft.quant.executor.ThreadStrategyExecutor;
import com.starsoft.quant.job.ModelJobRegister;
import com.starsoft.quant.service.ModelParamsService;
import com.starsoft.quant.service.QuantAcountService;

@RestController
@RequestMapping("/quant/acount")
public class QuantAcountController {
	
	private static Logger logger = LoggerFactory.getLogger(QuantAcountController.class);
	
	@Autowired
	AcountService acountService;

	@Autowired
	AcountPluginService acountPluginService;
	
	@Autowired	
	QuantAcountService quantAcountService;

	@Autowired
	ModelParamsService modelParamService;
	
	@Autowired
	ThreadStrategyExecutor threadExecutor;

	@Autowired
	ModelJobRegister modelJobRegister;

	@RequestMapping("/allenabled")
	public Map<String, Object> getAllParent(){
		UserContext context = UserService.getUserContext();
		List<BaseAcount> acounts = acountService.getParentAcount(context.getUserId());
		List<BaseAcount> enableQuant = new ArrayList<>();
		for(BaseAcount acount : acounts){
			QuantAcount quantAcount = quantAcountService.getAcount(acount.getAcountId());
			if (quantAcount != null) {
				enableQuant.add(acount);
			}
		}
		Map<String, Object> model = new HashMap<>();
		model.put("acounts", enableQuant);
		model.put("acount", context.getAcount());
		return model;
	}
	
	@RequestMapping("/modelconfigpage")
	public ModelAndView getAcountModel(HttpServletRequest request) {
		ModelAndView mv = new ModelAndView("/quant/acount/modelconfig");
		Integer acountId = getAcountId(request);
		mv.addObject("acountId", acountId);
		QuantAcount quantAcount = quantAcountService.getAcount(acountId);
		if (quantAcount != null) {
			List<QuantModelParam> params = modelParamService.getModelParams(quantAcount.getModelCode());
			mv.addObject("params", params);
		}
		return mv;
	}
	
	@RequestMapping("/modelconfig.json")
	public Map<String, Object> getModelConig(HttpServletRequest request) {
		Map<String, Object> model = new HashMap<>();
		Integer acountId = getAcountId(request);
		QuantAcount quantAcount = quantAcountService.getAcount(acountId);
		model.put("acount", quantAcount);

		BaseAcount baseAcount = acountService.getAcount(acountId);
		List<BaseAcount> allAcounts = acountService.getSunAcount(baseAcount);
		allAcounts.add(0, baseAcount);
		
		if (quantAcount != null) {
			List<Map<String, Object>> params = new ArrayList<>();
			for (BaseAcount oneAcount : allAcounts) {
				QuantAcount oneQuantAcount = quantAcountService.getAcount(oneAcount.getAcountId());
				Map<String, Object> oneResult = modelParamService.getAcountModelParamsMap(oneQuantAcount);
				oneResult.put("acountId", oneAcount.getAcountId());
				oneResult.put("acountName", oneAcount.getAcountName());
				oneResult.put("lastBackTest", oneQuantAcount.getLastBackTest());
				oneResult.put("testingStatus", threadExecutor.getStatusStr(oneAcount.getAcountId()));
				params.add(oneResult);
			}
			model.put("params", params);
		}
		return model;
	}

	@RequestMapping("/savemodelconfig")
	public Map<String, Object> saveAcountModel(QuantAcount quantAcount, HttpServletRequest request) {
		Integer acountId = quantAcount.getAcountId();
		QuantAcount oldQuantAcount = quantAcountService.getAcount(acountId);
		if(oldQuantAcount!=null){
			quantAcount.setLastBackTest(oldQuantAcount.getLastBackTest());
		}
		updateJob(quantAcount);
		
		quantAcountService.saveAcount(quantAcount);
		BaseAcount baseAcount = acountService.getAcount(acountId);
		acountPluginService.update(baseAcount, "Quant");
		
		return WebUtil.sucesseModel("保存成功");
	}
	
	@RequestMapping("/deletemodelconfig")
	public Map<String, Object> deleteAcountModel(QuantAcount quantAcount, HttpServletRequest request) {
		Integer acountId = quantAcount.getAcountId();
		quantAcount.setRunNomally(false);
		updateJob(quantAcount);
		acountPluginService.delete(acountService.getAcount(acountId), "Quant");
		return WebUtil.sucesseModel("删除成功");
	}
	
	@RequestMapping("/savemodelparams")
	public void saveAcountModelParams(QuantAcount quantAcount, ServletRequest request) {
		quantAcount = quantAcountService.getAcount(quantAcount.getAcountId());
		Map<String, Object> params = WebUtil.getParam(request);
		modelParamService.saveAcountModelParam(quantAcount, params);
	}
	
	private void updateJob(QuantAcount quantAcount) {
		try {
			modelJobRegister.updateQuantJob(quantAcount);
			logger.info("update job success");
		} catch (SchedulerException e) {
			logger.error("update job failed", e);
		}
	}
	
	@RequestMapping("/backtest")
	public Map<String, Object> backTest(QuantAcount quantAcount) throws Exception {
		String error = "";
		if (quantAcount != null && quantAcount.getAcountId() != null) {
			threadExecutor.backTest(quantAcount.getAcountId());
		} else {
			Integer acountId = UserService.getUserContext().getAcountId();
			BaseAcount baseAcount = acountService.getAcount(acountId);
			List<BaseAcount> acounts = acountService.getSunAcount(baseAcount);
			acounts.add(baseAcount);
			for (BaseAcount acount : acounts) {
				try {
					threadExecutor.backTest(acount.getAcountId());
				} catch (Exception e) {
					error += "\n" + acount.getAcountName() + e.getMessage();
				}
			}
		}
		return WebUtil.sucesseModel("开始回测" + error);
	}
	
	@RequestMapping("copyacount")
	public Map<String, Object> copyAcount() {
		Integer acountId = UserService.getUserContext().getAcountId();
		BaseAcount baseAcount = acountService.getAcount(acountId);
		if(baseAcount.getParentId()==null){
			BaseAcount sunAcount = acountPluginService.copyAsSun(baseAcount, null);
			return WebUtil.sucesseModel("Copy成功，"+ sunAcount.getAcountName());
		} else {
			return WebUtil.errorModel("Copy失败，不是父账户");
		}
	}

	private Integer getAcountId(HttpServletRequest request) {
		Integer acountId = null;
		String acountIdStr = request.getParameter("acountId");
		if (StringUtil.isEmpty(acountIdStr)) {
			acountId = UserService.getUserContext().getAcountId();
		} else {
			acountId = Integer.parseInt(acountIdStr);
		}
		return acountId;
	}
	
}
